//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/05/01
// Design Name:
// Module Name: spram
// Project Name: wujian100
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// base ahb addr is 0x4001_0000  none offset
//////////////////////////////////////////////////////////////////////////////////

module spram
   #(
    parameter                   ADDR_W = 12
    )
    (
    input                 [1  - 1 : 0] clk_i,
	  input                 [1  - 1 : 0] rst_n_i,
    input                 [1  - 1 : 0] en_i,
	  input                 [1  - 1 : 0] write_i,
	  input             [ADDR_W - 1 : 0] addr_i,
	  input                 [32 - 1 : 0] wdat_i,
    output                [1  - 1 : 0] rdy_o,
	  output                [32 - 1 : 0] rdat_o,
	  output                [1  - 1 : 0] intr_o
    );

localparam MEM_INDEX_W                 = ADDR_W-2;                             //索引值位宽
localparam MEM_DEP                     = 64;                                   //内存空间的深度 原值 {{(ADDR_W){1'b0}},{1'b1}}<<MEM_INDEX_W

reg                           [32-1:0] mem [MEM_DEP-1:0];                      //32bit寄存器组
reg                           [32-1:0] r2t_rdat_r;                             //读数据信号
wire                 [MEM_INDEX_W-1:0] mem_index_w;                            //32bit寄存器组读数据索引值

//////////////////////////////////////
//中断控制信号                       //
//////////////////////////////////////

reg                                    intr_temp_d;                            //中断寄存器有效位打拍信号
wire                                   intr_temp_w;                            //中断寄存器有效位信号
wire                                   intr_pos;                               //上升沿捕获

genvar index;

//////////////////////////////////////
//写寄存器信号                       //
//////////////////////////////////////

assign mem_index_w      = addr_i>>2;                                       //将地址转换为mem的索引值

//////////////////////////////////////
//读寄存器信号                       //
//////////////////////////////////////

assign rdat_o       = r2t_rdat_r;                                          //输出读数据
assign rdy_o        = 1'b1;                                                //始终有效

/************************************/
/*写寄存器操作                       */
/************************************/

generate
  for (index = 0; index < MEM_DEP ; index = index + 1)
  begin : MEM_LOOP

  always@(posedge clk_i or negedge rst_n_i)
  begin : MEM_PROG
    if (rst_n_i == 1'b0)
	    mem[index]             <= {(32){1'b0}};
    else if ((intr_pos == 1'b1)&&(index == {{(32-ADDR_W){1'b0}},{(ADDR_W){1'b0}}}))
    begin
      mem[index][0]          <= mem[index][0];                                 //其它位保持
      mem[index][1]          <= 1'b0;                                          //硬件复位中断标志位
      mem[index][32-1:2]     <= mem[index][32-1:2];                            //其它位保持
    end
	  else if ((en_i == 1'b1)&&(write_i == 1'b1)&&(index == {{(32-ADDR_W){1'b0}},{mem_index_w}}))
	    mem[index]      <= wdat_i;
	  else
	    mem[index]      <= mem[index];
  end

  end
endgenerate

/************************************/
/*读寄存器操作                       */
/************************************/

always@(*)
begin : R2T_RDAT_R_PROG
  if ((en_i == 1'b1)&&(write_i == 1'b0))
    r2t_rdat_r          = mem[mem_index_w];
  else
    r2t_rdat_r          = {(32){1'b0}};
end

/************************************/
/*产生中断信号&硬件复位               */
/************************************/
assign intr_o           = (intr_pos == 1'b1) ? 1'b1 : 1'b0;                    //输出中断信号
assign intr_pos         = (intr_temp_w&(~intr_temp_d)) ? 1'b1 : 1'b0;          //提取上升沿
assign intr_temp_w      = (mem[0][1]) ? 1'b1 : 1'b0;                           //取第一个寄存器的第二位为中断信号

always@(posedge clk_i or negedge rst_n_i)
begin : INTR_TEMP_D_PROG
  if (rst_n_i == 1'b0)
    intr_temp_d         <= 1'b0;
  else
    intr_temp_d         <= intr_temp_w;
end

endmodule

  //   \begin{longtable}{|c|c|c|p{8cm}|}
	// \caption{rm_ahb_if模块接口}\\
	// % 表格“首页”显示内容
	// \toprule
	// 信号名称           & 方向    & 位数  & 描述     \\ \hline
	// \midrule
	// \endfirsthead
	// % “后续页面”表头显示内容
	// \multicolumn{4}{r}{Continued}\\
	// \toprule
	// 信号名称           & 方向    & 位数  & 描述     \\ \hline
	// %\midrule
	// \endhead

  // clk_i     & input  & 1    & 信箱寄存器时钟 \\ \hline       
  // rst_n_i   & input  & 1    & 信箱寄存器复位信号，低电平有效      \\ \hline     
  // en_i      & input  & 1    & 信箱寄存器使能信号，高电平有效     \\ \hline 
  // write_i   & input  & 1    & 信箱寄存器读写控制信号，高电平为写，低电平为读     \\ \hline    
  // addr_i    & input  & 12   & 信箱寄存器地址信号     \\ \hline     
  // wdat_i    & input  & 32   & 信箱寄存器写数据信号     \\ \hline     
  // rdy_o     & output & 1    & 信箱寄存器准备信号，高电平有效     \\ \hline    
  // rdat_o    & output & 32   & 信箱寄存器读数据信号     \\ \hline     
  // intr_o    & output & 1    & 信箱寄存器中断信号，高电平有效     \\ \hline     
  //   \end{longtable}

      
        
     
        
       
       
      
       
       